﻿// SMIL is a community project available under the Microsoft Public License (Ms-PL)
// Code is provided as is and with no warrenty – Use at your own risk
// View the project and the latest code at http://smil.codeplex.com/

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using System.Runtime.Serialization;
using DeepEarth.BingMapsToolkit.Client.MapGeometry;
using DeepEarth.BingMapsToolkit.Client.Common;
//using DeepEarth.BingMapsToolkit.Client.Common.Commanding;
//using DeepEarth.BingMapsToolkit.Client.Common.Entities;
using DeepEarth.BingMapsToolkit.Client.Controls;
using System.ServiceModel;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using SMIL.SPCommunication;
using Microsoft.Maps.MapControl;
using Map = Microsoft.Maps.MapControl.Map;
using Point = GisSharpBlog.NetTopologySuite.Geometries.Point;
//using IsolatedStorage = DeepEarth.BingMapsToolkit.Client.Common.IsolatedStorage;
using DeepEarth.BingMapsToolkit.Common.Entities;
using SMIL.Geometry.Render;



namespace SMIL.LayerPanel
{

    public class SPGeoRSSItem
    {
        public string title;
        public Guid guid;
        public string description;
        public string position;
        public string icon_url;
        public string link_url;
        public string overlay_url;

        public string georss_point;
        public string geo_lat, geo_long;

        private string[] image_extensions = new string[] { ".jpg", ".png" };

        #region inner class Detail
        public class Detail
        {
            public string fieldName;
            public string fieldType;
            public string value;
        }
        #endregion

        public Dictionary<string, Detail> details;

        public bool IsImage
        {
            get
            {
                if (link_url == null)
                    return false;

                foreach (string extension in image_extensions)
                    if (link_url.ToLower().EndsWith(extension))
                        return true;

                return false;
            }
        }


        public bool ContainsCoordinate
        {
            get
            {
                return georss_point != null || (geo_lat != null && geo_long != null);
            }
        }

        public double Latitude
        {
            get
            {
                if (geo_lat == null && georss_point != null)
                    geo_lat = (georss_point.Split(new char[] { ' ' }))[0];

                geo_lat = geo_lat.Replace(",", System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
                geo_lat = geo_lat.Replace(".", System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);

                return double.Parse(geo_lat);
            }
        }

        public double Longitude
        {
            get
            {
                if (geo_long == null && georss_point != null)
                    geo_long = (georss_point.Split(new char[] { ' ' }))[1];

                geo_long = geo_long.Replace(",", System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
                geo_long = geo_long.Replace(".", System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);

                return double.Parse(geo_long);
            }
        }
    }

    public enum SMILLayerType
    {
        SMIL
    }

    public class SMILLayerDefinition : LayerDefinition
    {
        public new SMILLayerType LayerType;
        public string[] ViewNames;
    }

    public class LayerPanel : DeepEarth.BingMapsToolkit.Client.Controls.TreeViewLayerPanel
    {
        //const string ISOKey = "SMIL.Client.WPXAP.LayerPanel";
        SPCommunication.ASMX.SPGeoRssSISoapClient sp_proxy;
        Dictionary<string, InfoTool.InfoToolParams> pindict = new Dictionary<string, InfoTool.InfoToolParams>();
        bool? isInDataField;

        //Render render;

        public LayerPanel()
        {
            this.DefaultStyleKey = typeof(LayerPanel);

            if (Layers != null && Layers.Count > 0)
                foreach (LayerDefinition ld in Layers)
                    UnloadLayer(ld);

            Loaded += LayerPanel_Loaded;
        }

        private void LayerPanel_Loaded(object sender, RoutedEventArgs e)
        {
            //render = new Render();

            if (Application.Current.Resources[ApplicationVariables.ApplicationVariables.IsInDataField.ToString()] != null)
                isInDataField = bool.Parse(Application.Current.Resources[ApplicationVariables.ApplicationVariables.IsInDataField.ToString()].ToString());
            

            if (Layers.Count == 0)
                Connect();
        }

        

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
        }

        public string SPSiteURI { get; set; }

        public string GeoRssURI { get; set; }

        public void Connect()
        {
            if (Layers != null && Layers.Count > 0)
                foreach (LayerDefinition ld in Layers)
                    UnloadLayer(ld);

            sp_proxy = SPCommunication.Proxy.GetProxy;
            sp_proxy.GetLayerListCompleted += sp_proxy_GetLayerListCompleted;
            sp_proxy.GetGeoRssForLayerCompleted += sp_proxy_GetGeoRssForLayerCompleted;

            //savePersistentState();

            sp_proxy.GetLayerListAsync(new SMIL.SPCommunication.ASMX.LayersRequest()
            {
                SiteUrl = SPSiteURI
            });
        }


        void sp_proxy_GetLayerListCompleted(object sender, SMIL.SPCommunication.ASMX.GetLayerListCompletedEventArgs e)
        {
            ObservableCollection<LayerDefinition> kl = new ObservableCollection<LayerDefinition>();
            if (e.Error != null)
                throw e.Error;

            

            foreach (SPCommunication.ASMX.LayerResponseObj lro in e.Result.Layers)
            {
                foreach (string viewname in lro.ViewNames)
                {
                    if (viewname.Length < 1)
                        continue;

                    SMILLayerDefinition kld = new SMILLayerDefinition()
                    {
                        ViewNames = lro.ViewNames.ToArray(),
                        LayerAlias = viewname,
                        LayerID = lro.Name + "/" + viewname,
                        LayerType = (SMILLayerType)Enum.Parse(SMILLayerType.SMIL.GetType(), lro.Type, true),
                        Selected = false,
                        Tags = lro.Name,
                        MinDisplayLevel = 5,
                        MaxDisplayLevel = 21
                    };

                    // Ordna lagret i Z-led baserat på typ
                    switch (kld.LayerType)
                    {
                        case SMILLayerType.SMIL:
                            kld.ZIndex = 4;
                            break;

                        default:
                            kld.ZIndex = 0;
                            break;
                    }

                    kl.Add(kld as LayerDefinition);
                }
            }

            // note, turn this on for production
            // 
            //compareAndloadPersistentState(kl.ToList());
            Layers = kl;
        }

        //private void compareAndloadPersistentState(List<LayerDefinition> kld)
        //{
        //    List<LayerDefinition> layerListState = IsolatedStorage.LoadData<List<LayerDefinition>>(ISOKey);

        //    if (layerListState != default(List<LayerDefinition>) && layerListState.Count == kld.Count)
        //    {
        //        for (int i = 0; i < layerListState.Count; i++)
        //        {
        //            // LayerID (Path i SP-listan), är lika oavsett språk 
        //            kld[i].Selected = (layerListState[i].LayerID == kld[i].LayerID) ? layerListState[i].Selected : false;
        //        }
        //    }
        //}

        //public void savePersistentState()
        //{
        //    if (Layers != null)
        //    {
        //        List<LayerDefinition> l = Layers.ToList();
        //        IsolatedStorage.SaveData<List<LayerDefinition>>(l, ISOKey);
        //    }
        //}

        protected override void LoadLayer(LayerDefinition layerDefinition)
        {
            SMILLayerDefinition kld = layerDefinition as SMILLayerDefinition;

            try
            {
                switch (kld.LayerType)
                {
                    case SMILLayerType.SMIL:
                        EnhancedMapLayer eml = Vector.GetLayerByID(layerDefinition.LayerID, MapInstance);

                        if (eml == null)
                        {
                            sp_proxy.GetGeoRssForLayerAsync(new SMIL.SPCommunication.ASMX.LayerRequest() { SiteUrl = SPSiteURI, SPListName = kld.Tags, SPViewName = kld.LayerAlias }, kld);
                        }
                        else
                        {
                            SetOverlayVisibility(kld, Visibility.Visible);
                        }

                        //savePersistentState();

                        break;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error loading layer <" + layerDefinition.LayerAlias + " / " + layerDefinition.LayerID + "> : " + ex.Message);
            }
        }

        protected override void UnloadLayer(LayerDefinition layerDefinition)
        {
            //savePersistentState();

            SMILLayerDefinition kld = layerDefinition as SMILLayerDefinition;

            switch (kld.LayerType)
            {
                case SMILLayerType.SMIL:

                    EnhancedMapLayer eml = Vector.GetLayerByID(layerDefinition.LayerID, MapInstance);

                    if (eml != null)
                        SetOverlayVisibility(kld, Visibility.Collapsed);

                    break;
            }
        }

        /*******************************************************************
         * 
         * SMIL rendering
         * 
         *******************************************************************/
        void sp_proxy_GetGeoRssForLayerCompleted(object sender, SMIL.SPCommunication.ASMX.GetGeoRssForLayerCompletedEventArgs e)
        {
            if (e.Error != null)
                throw e.Error;

            PopulateLayer((SMILLayerDefinition)e.UserState, e.Result.Response);
        }

        void PopulateLayer(SMILLayerDefinition l, XElement xml_layer)
        {
            XNamespace xmlns = "http://www.w3.org/2005/Atom";
            XNamespace georssns = "http://www.georss.org/georss";
            XNamespace geons = "http://www.w3.org/2003/01/geo/wgs84_pos#";

            if (xml_layer == null)
                return;

            var items = from item in xml_layer.Descendants("item")
                        select new SPGeoRSSItem()
                        {
                            title = (string)item.Element("title"),
                            description = (string)item.Element("description"),
                            georss_point = (item.Element(georssns + "point") != null) ? item.Element(georssns + "point").Value : null,
                            //geo_lat = (item.Element(geons + "lat") != null) ? item.Element(geons + "lat").Value : null,
                            //geo_long = (item.Element(geons + "long") != null) ? item.Element(geons + "long").Value : null,
                            icon_url = (string)item.Element("icon"),
                            link_url = (string)item.Element("link"),
                            overlay_url = (string)item.Element("checkoutoverlay_url"),

                            details = (from detail in item.Elements("details").Elements("detail")
                                       select detail).ToDictionary(param => param.Attribute("fieldName").Value.ToString(),
                                                                  param => new SPGeoRSSItem.Detail()
                                                                  {
                                                                      fieldName = param.Attribute("fieldName").Value.ToString(),
                                                                      fieldType = param.Attribute("type").Value.ToString(),
                                                                      value = param.Value.ToString()
                                                                  })
                        };

            

            CreatePushpinOverlay(items, l);
        }

        void CreatePushpinOverlay(IEnumerable<SPGeoRSSItem> layerData, SMILLayerDefinition layerDefinition)
        {
            //string layerName = layerDefinition.LayerID.Split(new char[]{'/'})[0];
            var pins = new ObservableCollection<VectorLayerData>();

            string listName = Application.Current.Resources[SMIL.ApplicationVariables.ApplicationVariables.List.ToString()] as string;

            string id = string.Concat("?id=", Application.Current.Resources[
                            SMIL.ApplicationVariables.ApplicationVariables.ItemID.ToString()]);

            

            switch (layerDefinition.LayerType)
            {
                case SMILLayerType.SMIL:

                    var vectorLayer = new EnhancedMapLayer(MapInstance)
                    {
                        ID = layerDefinition.LayerID,
                        ZIndex = 100, //layerDefinition.ZIndex,
                        LayerDefinition = layerDefinition,
                        MinZoomLevel = layerDefinition.MinDisplayLevel,
                        MaxZoomLevel = layerDefinition.MaxDisplayLevel,
                    };

                    var vectorLayerInfoTool = new MapLayer();

                    MapInstance.Children.Insert(MapInstance.Children.Count, vectorLayer);
                    MapInstance.Children.Insert(MapInstance.Children.Count, vectorLayerInfoTool);

                    foreach (SPGeoRSSItem si in layerData)
                    {
                        string layerDataId = string.Empty;
                        if (si.link_url.Contains('?'))
                            layerDataId = si.link_url.Substring(si.link_url.IndexOf('?'), si.link_url.Length - si.link_url.IndexOf('?'));

                        // i tags finns listnamnet
                        if (!string.IsNullOrEmpty(layerDataId) && (isInDataField ?? false))
                        {
                            if ((layerDefinition.Tags as string).Equals(listName) &&
                                id.ToUpper(System.Globalization.CultureInfo.CurrentCulture).Equals(layerDataId.ToUpper(System.Globalization.CultureInfo.CurrentCulture)))
                                continue;
                        }

                        
                        //if (si.link_url.Contains(
                        var pininfo = new InfoTool.InfoToolParams()
                        {
                            Guid = new Guid(si.details["guid"].value),
                            WKT = si.georss_point,
                            //WKT = si.details["GEOMETRY"].value,
                            //Status = si.details["Status"].value,
                            ViewName = layerDefinition.LayerAlias,
                            ViewNames = layerDefinition.ViewNames,
                            ListName = layerDefinition.Tags,
                            SPSiteURI = SPSiteURI,
                            Title = si.title,
                            Subtitle = layerDefinition.Tags + " -> " + layerDefinition.LayerAlias,
                            ObjectUrl = si.link_url,
                            IconUrl = (si.IsImage) ? si.link_url : si.icon_url,
                            //Layer = vectorLayerInfoTool,
                        };

                        DataContractSerializer ser = new DataContractSerializer(typeof(InfoTool.InfoToolParams));

                        if (!pindict.ContainsKey(pininfo.Guid.ToString()))
                            pindict.Add(pininfo.Guid.ToString(), pininfo);
                        else
                            pindict[pininfo.Guid.ToString()] = pininfo;
                        SMIL.Geometry.StyledGeometry styledGeometry = new Geometry.StyledGeometry();

                        if (isInDataField ?? false)
                            styledGeometry.RenderGeometries((Map)MapInstance, vectorLayer, pininfo.WKT, Geometry.RenderState.ViewingNoInfoBox, pininfo.toXML());
                        else    
                            styledGeometry.RenderGeometries((Map)MapInstance, vectorLayer, pininfo.WKT, Geometry.RenderState.ViewingWithInfoBox, pininfo.toXML());

                    }
                    break;
            }
        }

        //void rg_Selected(object sender, EventArgs args)
        //{
        //    SelectGeometry sg = sender as SelectGeometry;
        //    InfoTool.InfoToolParams pi = pindict[sg.ItemID];
        //    InfoTool.InfoTool it = new SMIL.Client.WPXAP.InfoTool.InfoTool(pi);

        //    System.Windows.Point point = GetViewPointByLocation(sg);

        //    Location location = MapInstance.ViewportPointToLocation(new System.Windows.Point { X = point.X, Y = point.Y });

        //    if (!pi.Layer.Children.Contains(it))
        //    {
        //        pi.Layer.AddChild(it,
        //            new Microsoft.Maps.MapControl.Location
        //            {
        //                Latitude = location.Latitude,
        //                Longitude = location.Longitude
        //            });
        //    }
        //}

        private System.Windows.Point GetViewPointByLocation(SelectGeometry selectGeom)
        {
            double lat = selectGeom.Geometry.Coordinate.Y;
            double lon = selectGeom.Geometry.Coordinate.X;

            System.Windows.Point point = MapInstance.LocationToViewportPoint(
                new Microsoft.Maps.MapControl.Location { Latitude = lat, Longitude = lon }
                );

            return point;
        }

        void SetOverlayVisibility(LayerDefinition layerDefinition, Visibility visibility)
        {
            var vl = Vector.GetLayerByID(layerDefinition.LayerID, MapInstance);

            if (vl != null)
            {
                vl.Visibility = visibility;
                return;
            }
        }
    }
}